

import 'dart:convert';
import 'package:trade/common/service/cache_service/wd_shared_preferences.dart';
import 'package:trade/common/service/i_service.dart';
import 'package:trade/common/util/event_bus/event_bus.dart';
import 'package:trade/common/util/exchange_logger/exchange_logger.dart';

/// LRU二级缓存, 注意项目所有key/value缓存务必通过service.cache来实现
class CacheService extends IService{

  static final String wdCacheKey = "wdCacheKey";
  static final int _len = 168000; // 内存活跃总数(节点总数上限)
  final caches = <String, CacheNode>{}; // 所有节点
  CacheNode? _first; // 头节点
  CacheNode? _last;  // 尾节点
  /// 监听某一存储数据变化
  void addListener(String eventName, EventCallback callback){
    /// + wdCacheKey防止与外面有重复冲突
    eventBus.addListener(eventName + wdCacheKey, callback);
  }
  /// dispose时务必移除监听,以防泄漏
  void removeListener(String eventName, EventCallback callback){
    eventBus.removeListener(eventName + wdCacheKey, callback);
  }


  Future setValue(String key, dynamic value) async {
    /// 先存到内存中
    _putToMemory(key, value);
    return Future((){
      if(null != value){
        var diskValue = _sharedPreferences.getValue(key);
        if(diskValue != value){
          /// eventBus发通知更新
          eventBus.fireListener(key+ wdCacheKey, argument: value);
          /// 再把新值存到disk中
          _sharedPreferences.setValue(key, value);
        }
      }
    });
  }

  void setMap(String key, Map<String, dynamic> value){
    try{
      setString(key, jsonEncode(value));
    }catch (e){
      logger.d('cache setMap($value) error: ${e.toString()}');
    }
  }

  Map<String, dynamic>? getMap(String key, { Map<String, dynamic>? defaultValue }){
    try{
      String? value = getString(key);
      if(null == value) return defaultValue;
      Map<String, dynamic> res = jsonDecode(value) as Map<String, dynamic>;
      return res;
    }catch (e){
      logger.d('cache getMap error: ${e.toString()}');
    }
    return {};
  }



  void setString(String key, String value) => setValue(key, value);
  void setStrings(String key, List<String> values){
    try{
      setString(key, jsonEncode(values));
    }catch (e){
      logger.d('cache setStrings($values) error: ${e.toString()}');
    }
  }

  List<String>? getStrings(String key, { List<String>? defaultValue }){
    List<String> data = [];
    try{
      String? value = getString(key);
      if(null == value) return defaultValue;
      List<dynamic> list = jsonDecode(value);
      data.addAll(list.map<String>((e) => e).toList());
    }catch (e){
      logger.d('cache getStrings error: ${e.toString()}');
    }
    return data;
  }

  void setInt(String key, int value) => setValue(key, value);
  void setInts(String key, List<int> values){
    try{
      setString(key, jsonEncode(values));
    }catch (e){
      logger.d('cache setInts error: ${e.toString()}');
    }
  }

  List<int>? getInts(String key, {List<int>? defaultValue}){
    List<int> data = [];
    try{
      String? value = getString(key);
      if(null == value) return defaultValue;
      List<dynamic> list = jsonDecode(value);
      data.addAll(list.map<int>((e) => e).toList());
    }catch (e){
      logger.d('cache getInts error: ${e.toString()}');
    }
    return data;
  }

  void setNum(String key, num value) => setValue(key, value);
  void setNumList(String key, List<num> values){
    try{
      setString(key, jsonEncode(values));
    }catch (e){
      logger.d('cache setNumList error: ${e.toString()}');
    }
  }

  List<num>? getNumList(String key, {List<num>? defaultValue}){
    List<num> data = [];
    try{
      String? value = getString(key);
      if(null == value) return defaultValue;
      List<dynamic> list = jsonDecode(value);
      data.addAll(list.map<num>((e) => e).toList());
    }catch (e){
      logger.d('cache getNumList error: ${e.toString()}');
    }
    return data;
  }

  void setBool(String key, bool value) => setValue(key, value);
  void setBoolList(String key, List<bool> values){
    try{
      setString(key, jsonEncode(values));
    }catch (e){
      logger.d('cache setBoolList error: ${e.toString()}');
    }
  }

  List<bool>? getBoolList(String key, {List<bool>? defaultValue}){
    List<bool> data = [];
    try{
      String? value = getString(key);
      if(null == value) return defaultValue;
      List<dynamic> list = jsonDecode(value);
      data.addAll(list.map<bool>((e) => e).toList());
    }catch (e){
      logger.d('cache getBoolList error: ${e.toString()}');
    }
    return data;
  }


  void _putToMemory(String key, dynamic value) {
    CacheNode? node = caches[key];
    if(null == node) { /// 新元素
      /// 如果超过元素容量
      if(caches.length >= _len){
        caches.remove(_last?.key);
        _removeLast();
      }
      /// 新建节点
      node = new CacheNode(key, value);
      caches[key] = node;
    }else {
      /// 已经存在的元素用新值覆盖
      node.value = value;
    }
    /// 将元素移到首部
    _moveToFirst(node);
  }

  void _removeLast(){
    if(null != _last){
      _last = _last?.pre;
      if(null == _last){
        _first = null;
      }else {
        _last?.next = null;
      }
    }
  }

  void _moveToFirst(CacheNode node) {
    if(_first == node) return;

    if(null != node.next){
      node.next?.pre = node.pre;
    }

    if(null != node.pre){
      node.pre?.next = node.next;
    }

    if(node == _last){
      _last = _last?.pre;
    }

    if(null == _first || _last == null){
      _first = _last = node;
      return;
    }
    node.next = _first;
    _first?.pre = node;
    _first = node;
    _first?.pre = null;
  }

  T? get<T>(String key){
    CacheNode? node = caches[key];
    if(null == node){
      try{
        dynamic value = _sharedPreferences.getValue(key);
        if(value is T){
          return value;
        }
        if(null != value){
          _putToMemory(key, value);
          return value;
        }
        return null;
      } catch(e){

      }
      return null;
    }else {
      /// 将访问的节点移到首部
      _moveToFirst(node);
    }
    return node.value;
  }

  String? getString(String key, {String? defaultValue}){
    String? ret = get<String>(key);
    if(null == ret && null != defaultValue){
      return defaultValue;
    }
    return ret;
  }

  bool? getBool(String key, {bool? defaultValue}){
    bool? ret = get<bool>(key);
    if(null == ret && null != defaultValue){
      return defaultValue;
    }
    return ret;
  }
  double? getDouble(String key, {double? defaultValue}){
    double? ret = get<double>(key);
    if(null == ret && null != defaultValue){
      return defaultValue;
    }
    return ret;
  }
  int? getInt(String key, {int? defaultValue}){
    int? ret = get<int>(key);
    if(null == ret && null != defaultValue){
      return defaultValue;
    }
    return ret;
  }
  num? getNum(String key, {num? defaultValue}){
    num? ret = get<num>(key);
    if(null == ret && null != defaultValue){
      return defaultValue;
    }
    return ret;
  }

  dynamic getValue(String key){
    return get(key);
  }

  void removeValue(String key){
    CacheNode? node = caches[key];
    if(null != node){
      if(null != node.pre){
        node.pre?.next = node.next;
      }
      if (null != node.next){
        node.next?.pre = node.pre;
      }
      if(node == _first){
        _first = node.next;
      }
      if(node == _last){
        _last = node.pre;
      }
    }
    caches.remove(key);
    _sharedPreferences.removeValue(key);
  }

  void clear() {
    _first = null;
    _last = null;
    caches.clear();
    _sharedPreferences.clearAllValue();
  }
  @override
  Future<void>? init() async {
    await _sharedPreferences.init();
    return null;
  }
  final WDSharedPreferences _sharedPreferences = WDSharedPreferences();

}

class CacheNode<T> {
  late final String key;
  T? value;
  CacheNode? pre;
  CacheNode? next;

  CacheNode(String key, T? value) {
    this.key = key;
    this.value = value;
  }
}